package models.crawlers;

import models.crawlers.common.*;
import models.entities.ProductEntity;
import models.helpers.StringHelper;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

public class Muztorg extends ShopCrawler {
    private models.crawlers.common.DocumentCache documentCache;
    public Muztorg(){
        this(false);
    }
    public Muztorg(boolean useProxy) {
        crawlerMainUrl = "http://www.muztorg.ru";
        this.useProxy = useProxy;
    }

    protected WebSiteInfo initializeWebSiteInfo() throws IOException {
        SitePathInfo categoryPath = new SitePathInfo();
        categoryPath.url = crawlerMainUrl + "/cat/";
        categoryPath.title = "MUZTORG";
        return getWebSiteInfo(categoryPath.url, categoryPath);
    }

    private WebSiteInfo getWebSiteInfo(String url, SitePathInfo categoryPath) throws IOException {
        Document categoriesPage = downloadPage(url);
        int categoriesCount = getCategoriesCount(categoriesPage);
        int productsCount = getProductsCount(categoriesPage);
        return new WebSiteInfo(categoryPath, categoriesCount, productsCount);
    }

    private int getProductsCount(Document categoriesPage) {
        Elements childElements = categoriesPage.select("#con_right .vendrow span.small .tovcount");
        int productsCount = 0;
        for (Element element : childElements) {
            String pCount = element.text().replace("(", "").replace(")", "");
            if (StringHelper.isNumeric(pCount)) {
                productsCount += Integer.parseInt(pCount);
            }
        }
        return productsCount;
    }

    private int getCategoriesCount(Document categoriesPage) {
        Elements categories = categoriesPage.select("#con_right .vendrow ul.small");
        int categoriesCount = categories.size();
        for (Element element : categories) {
            Elements lis = element.select("li");
            categoriesCount += lis.size();
        }
        return categoriesCount;
    }


    @Override
    public List<CategoryInfo> getCategories(String url) throws IOException {
        Elements elements = getCategoryChildElements(url);
        List<CategoryInfo> categories = new ArrayList<CategoryInfo>();
        for (Element element : elements) {
            Elements childCategoryElement = element.select("a");
            String childCategoryTitle = childCategoryElement.text();
            String childCategoryUrl = getSourceUrl(childCategoryElement.attr("href"));
            CategoryInfo categoryInfo = new CategoryInfo(childCategoryTitle, childCategoryUrl);
            categories.add(categoryInfo);
        }
        return categories;
    }


    private Elements getCategoryChildElements(String url) throws IOException {
        Document categoryPage = downloadPage(url);
        if (url.equals("http://www.muztorg.ru/cat/")) {
            Elements childElements = categoryPage.select("#con_right .vendrow span.small");
            return childElements;
        } else {
            Elements elements = categoryPage.select("#con_left .leftcolumn div.h3.bb");
            if (elements.size() > 0) {
                Element h = elements.get(0);
                if (h.text().trim().equals("По категориям:")) {
                    Element child = h.nextElementSibling();
                    return child.select("li");
                } else {
                    Elements el = new Elements();
                    return el;
                }
            } else {
                return elements;
            }
        }
    }

    @Override
    public List<ProductInfo> getProducts(String url, int pageNumber) throws IOException {
        if (pageNumber > 1)
            url = String.format("%1$spage%2$s/", url, pageNumber);
        Document categoryPage = downloadPage(url);
        documentCache = new DocumentCache(url, categoryPage);
        Elements products = categoryPage.select(".tovar");
        List<ProductInfo> productInfos = new ArrayList<ProductInfo>();
        for (Element productElement : products) {
            ProductInfo productInfo = new ProductInfo();
            Elements productAnchorElement = productElement.select(".r2 .h a");
            productInfo.title = productAnchorElement.text().trim();
            productInfo.url = getSourceUrl(productAnchorElement.attr("href"));
            productInfos.add(productInfo);
        }
        return productInfos;
    }


    private String getProductListPageUrl(String url, int pageNumber) {
        return String.format("%1$spage%2$s/", url, pageNumber);
    }

    protected String getProductSourceId(String currentProductUrl) {
        String result = currentProductUrl.substring(currentProductUrl.indexOf("/details/") + 9, currentProductUrl.lastIndexOf("/"));
        return result;
    }



    @Override
    protected Integer findNextPage(Integer pageNumber, String url) throws IOException {
        Document productList;
        if (documentCache != null) {
            String url1 = getProductListPageUrl(url, pageNumber);
            if (documentCache.cacheUrl.equals(url1))
                productList = documentCache.document;
            else
                productList = downloadPage(url1);
        } else {
            String url1 = getProductListPageUrl(url, pageNumber);
            productList = downloadPage(url1);
        }
        Elements listingRight = productList.select(".listing .right");
        if (listingRight.size() == 0) {
            return null;
        } else {
            Element pager = listingRight.get(0);
            Element selected = pager.select(".s").get(0);
            Element next = selected.nextElementSibling();
            if (StringHelper.isNumeric(next.text()) || next.text().equals("»")) {
                if (next.text().equals("»")) {
                    return pageNumber + 1;
                } else {
                    Integer nextPage = Integer.parseInt(next.text());
                    return nextPage;
                }

            } else {
                return null;
            }
        }
    }

    protected int getCategoryProductsCount(String url) throws IOException {
        Document productPage = downloadPage(url);
        Elements elements = productPage.select(".listing .left");
        if (elements.size() > 0) {
            String productCountElement = productPage.select(".listing .left").get(0).text();
            String countString = productCountElement.substring(productCountElement.indexOf("(") + 1, productCountElement.indexOf(")")).replace("Всего: ", "");
            if (StringHelper.isNumeric(countString)) {
                return Integer.parseInt(countString);
            }
        }
        return 0;
    }

    @Override
    public ProductEntity getProduct(String url) throws IOException, ProductParsingException {
        try {
            Document productPage = downloadPage(url);
            ProductEntity productEntity = new ProductEntity();
            Elements description = productPage.select(".spec_desc_inner .d .t");
            Elements priceElements = productPage.select(".price #price");
            Elements nameElements = productPage.select(".name");
            Elements shortDescElements = nameElements.select(".d");
            Elements pNameElements = nameElements.select("h1");
            if (shortDescElements.size() > 0)
                productEntity.shortDescription = shortDescElements.get(0).text().trim();
            if (pNameElements.size() > 0)
                productEntity.title = pNameElements.text().trim();
            if (priceElements.size() > 0) {
                Elements roznPrice = priceElements.select(".rozn_price");
                Elements intPrice = priceElements.select(".int_price");
                if (roznPrice.size() > 0) {
                    String priceText = roznPrice.text().replace("руб.", "").replace(" ", "");
                    if (StringHelper.isNumeric(priceText))
                        productEntity.price = Double.parseDouble(priceText);
                }
                if (intPrice.size() > 0) {
                    String priceText = intPrice.text().replace("руб.", "").replace(" ", "");
                    if (StringHelper.isNumeric(priceText))
                        productEntity.discountPrice = Double.parseDouble(priceText);
                }
            }
            productEntity.description = description.html();
            productEntity.brandName = getBrandName(productPage);
            productEntity.brandImageUrl = getBrandImageUrl(productPage);
            addPictures(productEntity, productPage);
            return productEntity;
        } catch (Exception ex) {
            throw new ProductParsingException(ex);
        }
    }


    private String getBrandImageUrl(Document productPage) {
        Elements brandLogo = productPage.select(".about .logo");
        Elements brandImage = brandLogo.select("img");
        return MessageFormat.format("{1}{0}", brandImage.attr("src"), crawlerMainUrl);
    }

    private void addPictures(ProductEntity productEntity, Document productPage) throws Exception {
        Elements picture = productPage.select(".main .picture a img");
        if (picture.size() > 0) {
            String pictureUrl;
            if (useProxy) {
                pictureUrl = picture.attr("src");
            } else {
                pictureUrl = MessageFormat.format("{1}{0}", picture.attr("src"), crawlerMainUrl);
            }
            productEntity.pictureUrls.add(pictureUrl);
            //productEntity.picturesData.add(getPictureData(pictureUrl));
        }
    }

    private String getBrandName(Document productPage) throws IOException {
        Elements brandLogo = productPage.select(".about .logo");
        Elements brandLinks = brandLogo.select("a");
        String brandName = brandLinks.get(0).text().trim().replace("Музыкальные инструменты ", "");
        return brandName;
    }
}
